博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
正则表达式
阅读量:5257 次
发布时间:2019-06-14

本文共 12226 字,大约阅读时间需要 40 分钟。

  • 正则表达式是用来进行文本处理的技术,是语言无关的,在几乎所有语言中都有实现。javascript中还会用得到。
  • 一个正则表达式是由普通字符串以及特殊字符字符(称为元字符)组成的文字模式,该模式描述在查找文字主体时,待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行比较。
  • 就像通配符“*.jpg”、“%ab%”,它是对字符串进行匹配的特殊字符串。
  • 正则表达式是非常复杂的,不要希望一次能掌握,理解正则表达式能做什么(字符串的匹配,字符串的提取,字符串的替换),掌握常用的正则表达式语法,以后用到再查就行。
  • 找工作的亮点,后面项目中的采集器,敏感词过滤、URLRewite、Validator也会涉及到正则表达式。
  • 正则表达式是对字符串进行操作的
  • 理解元字符是一个必须攻克的难关

(1).:匹配除\n之外的任何一个字符。例如正则表达式“b.g”能匹配如下字符串:“big”、“bug”、“b g”,但是不匹配“buug”,"b..g"可以匹配“buug”。

(2)[]:匹配括号中的任何一个字符。例如正则表达式“b[aui]g”匹配bug、big和bag,但是不匹配beg、baug。也可以在括号中使用连字符“-”来指定字符的区间。例如正则表达式[0-9]可以匹配任何数字字符,这样正则表达式"a[0-9]c"等价于"a[0123456789]c"就可以匹配“a0c”、“a1c”,"a2c"等字符串;还可以制定多个区间,例如“[A-Za-z]”可以匹配任何大小的字母,“[A-Za-z0-9]”,可以匹配任何的大小写字母或者数字。

匹配11-20之间的数字,正则表达式为[12][0-9],不能写成[10-29],因为这里的10和29只是表示字符1 或0 2或9

(2)|:将这个匹配条件进行逻辑"或"运算。‘z|food’能匹配“z”或“food”。‘(z|f)ood’则匹配“zood”或“food”。注意^$。[ab]等价于a|b。匹配的时候将"|"左右两边分别作为一个整体

(3)():将()之间括起来的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域,这个元字符在字符串提取的时候非常有用。把一个字符串表示为一个整体。改变优先级,定义提取组两个作用。

限定符:限定前面的表达式出现的次数。

(4)*:匹配多个在它之前的子表达式,和通配符没有关系。例如正则表达式“zo*”等同于“z(o*)”能匹配“z”,"zo"以及"zoo",因此"*“意味着能够匹配任意字符串。

”z(b|c)*“可以匹配zb,zbc,zcb,zcccc,zbbbcc。”z(ab)*"能匹配zab,zabab(用括号表示优先级)。

(5)+:匹配前面的子表达式一次或多次,和*对比(0到多次)。例如正则表达式,9+匹配9,99,999等。"zo+“以及”zoo",不能匹配"z“。

(6)?:匹配前面的子表达式零次或一次。例如”do(es)?"可以匹配"do“,”does"。一般用来匹配"可选部分“。

(7){n}:匹配确定的n次。”zo{2}“-zoo。例如”e{2}“不能匹配”bed“中的”e“,但是能匹配”seed“中的两个”e“。

(8){n,}:至少匹配n次。例如”e{2,}“不能bed中的”e“,但能匹配”seeeeeed“中的所有”e“。

(9){n,m}:最少匹配n次最多匹配m次。”e{1,3}“

 (10)^匹配一行的开始,例如正则表达式”^regex“能够匹配字符串“^regex我会用”的开始,但是不能匹配“我会用regex”。^另外一种意思:非[^0-9],放在中括号里面表示非,其余地方都表示为匹配一行的开始

(11)$匹配行结束符。例如正则表达式“浮云$”,能够匹配字符串“一切都是浮云”的末尾,但是不能匹配字符串“浮云呀”。

  •  简写表达式

♦注意简写表达式是不考虑转义符的。这里的\就表示字符\,而不是c#级别的\,在c#代码中使用@或\双重转义。区分c#级别的转义和正则表达式级别的转义,恰好c#的转义\和正则表达式级别的转义符都是\而已。正则表达式的转义是在c#之后的(层层盘剥)。把c#的转义想成%就明白了@“\."就是"\.“这个普通的字符串,只不过在正则表达式来看,它有了特殊的含义@”\d“或者”\\d“。

-》\d:代表一个数字,等同于[0-9]

-》\D:代表非数字,等同于[^0-9]

-》\s:代表换行符、Tab制表符等空白字符(一般我们用[\s\S]来匹配任意字符串)

-》\S:代表非空白字符

-》\w:匹配字母或数字或下划线或汉字,即能组成单词的字符。

-》\W:非\w,等同于[^\W]

d:digital;s:space;w:word。大写就是”非“

  • 简单正则表达式的练习

  1.匹配正确的邮政编码   ^\d{6}$

  2.判断是是不是身份证号码(15位数字或18位数字后面可能有X)^(\d{15}|\d{18}[xX]?)$   或者^(\d{15}|\d{17}[dxX])$

  3.匹配国内电话号

    -》三位或四位区号-八位或七位电话号码 ^((\d{3}|\d{4})-(\d{8}|\d{7}))$

    -》11位数字的手机号码 ^\d{11}$(不严格)

    -》服务电话10086、10010、95599、95588等  ^((100|955)\d{2})$(不严格)

  •  .Net的正则表达式

♦正则表达式在.Net中就是用字符串表示,这个字符串格式比较特殊,无论多么特殊,在c#语言看来都是普通的字符串,具体什么含义由Regex类内部进行分析。

♦如何匹配大于10小于20的字符串^[1][1-9]$(正则表达式是对字符串的操作)

♦正则表达式(Regular Expression)的主要类:Regex

♦常用的四种情况:(C#语法)

-》判断是否匹配Regex.IsMatch(”字符串","正则表达式“)

-》字符串提取:Regex.Match(”字符串","要提取的字符串的正则表达式")//只能提取一个(提取一次)

-》字符串提取(循环提取所有)Regex.Matchs()//可以提取所有匹配的字符串

-》字符串替换Regex.Replace("字符串",“正则”,“替换内容”)

string str = "fjdjfdfd fj123jdkfjdjfdjf45dfjkdjfkdj1233";            Match m=Regex.Match(str,@"\d+");//返回第一个匹配的字符串            if (m.Success)            {                Console.WriteLine("匹配到的字符串为{0}",m.Value);                Console.WriteLine("匹配的字符串的起始位置是{0}",m.Index);                Console.WriteLine("匹配到的字符串长度为{0}", m.Length);            }            MatchCollection mc=Regex.Matches(str,@"\d+");//匹配所有的字符串            Console.WriteLine("==================");            //用for循环遍历            for (int i = 0; i < mc.Count; i++)            {                Match m1 = mc[i];                Console.WriteLine("匹配到的字符串为{0}", m1.Value);                Console.WriteLine("匹配的字符串的位置是{0}", m1.Index);                Console.WriteLine("匹配到的字符串长度为{0}", m1.Length);                Console.WriteLine();            }            Console.WriteLine("===================");            //foreach遍历            foreach(Match item in mc){                Console.WriteLine(item.ToString());            }            Console.ReadKey();
View Code
  • 难点:利用圆括号对匹配的结果进行分组

(案例,提取文本文件里特定格式的字符串)

//读取html文本
//
//
//
//
// // ......... 里的图片路径 string html = System.IO.File.ReadAllText("美女们.htm",Encoding.Default); string regex = "src=\"(.+)\"";//正则表达式中圆括号有分组的功能,从左往右数圆括号,一次为Groups[1]、Groups[2]、Groups[3]...... MatchCollection mc=Regex.Matches(html, regex); foreach (Match m in mc) { Console.WriteLine(m.Groups[1]); } Console.ReadKey();

再如例子

string str = "012345";                                 //   12  3    4    5            string regex = @"((\d(\d))(\d))(\d)";            Match m = Regex.Match(str, regex);            Console.WriteLine(m.Value);//结果为0123            Console.WriteLine("第1组为:"+m.Groups[1]);//结果为0123            Console.WriteLine("第2组为:" + m.Groups[2]);//结果为012            Console.WriteLine("第3组为:" + m.Groups[3]);//结果为01            Console.WriteLine("第4组为:" + m.Groups[4]);//结果1            Console.WriteLine("第5组为:" + m.Groups[5]);//结果为0            Console.ReadKey();

上述代码中,利用了正则表达式圆括号分组功能,直接将匹配到的字符串进行分组以提取我们自己所需要的内容。

所以,我们可以尝试用正则匹配一个文件的全路径的文件名和后缀名

string file = @"C:\123\4565\789\abcd.mp3";            string regex = @"\\([^\\]+)(\.[^\\]+)$";            MatchCollection m = Regex.Matches(file, regex);            foreach (Match item in m)            {                Console.WriteLine(item.Value);//匹配结果为abcd.mp3                Console.WriteLine(item.Groups[1].Value);//匹配结果为abcd                Console.WriteLine(item.Groups[2].Value);//匹配结果为.mp3            }            Console.ReadKey();

易错题目:

string s=@"((\d)(\w))+";            string r="1a2b3c";            Match m = Regex.Match(r,s);            MatchCollection mc   =Regex.Matches(r,s);            Console.WriteLine(m.Groups[0]);//结果为1a2b3c            Console.WriteLine(m.Groups[1]);//结果为3c,因为第一组(即第一个括号)是匹配一个数字和一个字符。本来最先匹配到的是1a,但后面陆续被2b,3c覆盖了所以最后结果为3c。好比一个变量第一次存储1a,第二次改为存储2b,第三次为3c            Console.WriteLine(m.Groups[2]);//结果为3            Console.WriteLine(m.Groups[3]);//结果为c            Console.ReadKey();        }

若上述易错题中,将((\d)(\w)+),那么匹配的第一组就是1a2b3c,因为第一组(第一个括号内)匹配的表达式为为一个或者多个\d\w

  • 匹配IP地址,4段用.分割的最多三位数字。192.168.54.77,假设333.3333.3.33也是正确的 ^(\d{1,3}(\.\d{1,3}){3})$

  说明:以上匹配IP地址的正则表达式其实严格意义上说是不正确的。IP地址的每个节点其实都是0-255的数字

  严谨的IP:^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$

  6.匹配Url(比如、ftp://127.0.0.1/1.txt)

   说明:url是uniform resource locator

   组成://地址/目录?参数1=参数值&参数1=参数值....

   简单解释:协议http(hyper text translate protocal)传输协议  网站 ;协议 ftp(file translate protocal ) 下载;

        端口:入口

        目录:定位一台计算机下的目录文件下

  匹配url的正则表达式:^\W+://.+$ 

   

string regex =  @"^(https?|ftp)://([^:]+?)(:\d+)?(/[^\?]+?(\?\w+=\w+(&\w+=\w+)*)?)?$";           // regex =   @"(.+?)://(.+?)(:\d+)?(/.+?)\?(.+)";//也可以            string url1 = @"http://www.123.com:8081/1.html?k=1&y=2";            string url2 = @"http://www.123.com/yangzhongke?wd=1";            Console.WriteLine(Regex.IsMatch(url1,regex));//结果为true            Console.WriteLine(Regex.IsMatch(url2,regex));//结果为true            Console.ReadKey();

 

  • 正则表达式的贪婪模式(难点)
//贪婪模式:从左往右递减,正则表达式只有两个权级,一个是尽可能匹配,一个尽可能不匹配            string  str="12345";            string regex=@"(\d+)(\d+)(\d+)";            Match mc=Regex.Match(str,regex);            Console.WriteLine(@"第一个\d+匹配到的为:"+mc.Groups[1]);//结果匹配为123            Console.WriteLine(@"第二个\d+匹配到的为:"+mc.Groups[2]);//结果匹配为4            Console.WriteLine(@"第三个\d+匹配到的为:"+mc.Groups[3]);//结果匹配为5            Console.WriteLine("==========================");            string regex1 = @"(\d*?)(\d*)(\d+)";//问号表示取消贪婪模式            Match mc1 = Regex.Match(str, regex1);            Console.WriteLine(@"第一个\d+匹配到的为:" + mc1.Groups[1]);//结果为不匹配            Console.WriteLine(@"第二个\d+匹配到的为:" + mc1.Groups[2]);//结果匹配为1234            Console.WriteLine(@"第三个\d+匹配到的为:" + mc1.Groups[3]);//结果匹配为5            Console.ReadKey();

 

那么,接下来我们可以尝试用正则表达式来实现Path类的几个静态方法:GetDirectoryName()、GetFileName()、GetExtension()、GetFileNameWitoutExtension()

string file = @"C:\123\4565\789\abcd.mp3";                   string regex = @"((.:)\\.+\\)((.+)(\..+))";            Match mc = Regex.Match(file, regex);            Console.WriteLine("匹配的原始数据为:" + mc.Value);            Console.WriteLine("文件所在的磁盘为:" + mc.Groups[2]);            Console.WriteLine("文件的全路径为:" + mc.Groups[1]);            Console.WriteLine("文件的文件名为:" + mc.Groups[3]);            Console.WriteLine("文件的后缀名为:" + mc.Groups[5]);            Console.WriteLine("文件的去后缀名的文件名为:" + mc.Groups[4]);                    // @"((.:)\\.+\\)((.+)(\..+))";            Console.WriteLine("===============");            string file1= @"C:\abcd.mp3";            regex = @"((.:)\\(.+\\)?)((.+)(\..+))";            Match mc1 = Regex.Match(file1,regex);            Console.WriteLine("匹配的原始数据为:" + mc1.Value);            Console.WriteLine("文件所在的磁盘为:" + mc1.Groups[2]);            Console.WriteLine("文件的全路径为:" + mc1.Groups[1]);            Console.WriteLine("文件的文件名为:" + mc1.Groups[4]);            Console.WriteLine("文件的后缀名为:" + mc1.Groups[6]);            Console.WriteLine("文件的去后缀名的文件名为:" + mc1.Groups[5]);            Console.ReadKey();
  •  案例讲解

1.练习从网站上下载图片

搭建一个服务器(运行CassiniDev.exe),将我们计算机硬盘里存储的html文件的物理路径复制到CasiniDev PysicalPath下面的文本框内,点击start,即可以生成一个可访问的网址

步骤:

(1)运行CassiniDev.exe

 (2)将default.htm所在的物理路径放入CassiniDev 地下的PysicalPath下的文本框内

(3)点击start

代码: 

     WebClient wc =new WebClient();//用来从网站上下载资源的类            string html = wc.DownloadString("http://localhost:8080/default.htm");            string r= @"";               // r = @"

 2.从网页上提取Email

WebClient wc = new WebClient();            wc.Encoding = Encoding.UTF8;//因为该html文件的charset=UTF-8;            string htmlText = wc.DownloadString("http://localhost:8080/大家留下email交友吧_email_天涯社区.htm");            string regex = @"[\da-zA-Z\.\-_]+@\w+\.[a-zA-Z]+";            MatchCollection mc = Regex.Matches(htmlText, regex);            foreach (Match item in mc)            {                Console.WriteLine(item.Value);                //System.IO.File.WriteAllText(@"E:\上课\第12天\课堂代码\下载Email\bin\Debug\结果.txt",item.Value);            }            Console.ReadKey();

 3.从招聘网页上提取岗位名称

WebClient wc = new WebClient();            string htmltxt = wc.DownloadString("http://localhost:8080/【上海,IT-管理,计算机软件招聘,求职】-前程无忧.htm");            string regex = @"(.+)";            MatchCollection mc = Regex.Matches(htmltxt,regex);            foreach( Match item in mc)            {                Console.WriteLine(item.Groups[1]);            }            Console.ReadKey();
  •  正则表达式替换的简单说明

说明:Regex.Replace(string 需要操作的字符串,string 需要替换的字符串,string替换为的字符串)跟string <string>.Replace()相似。正则表达式相对功能更强大

代码:

//将 "2013年8月9日"替换为“2013-8-9”            //解法一            string str = "2013年8月9日";            str = Regex.Replace(str, "年|月", "-");            str = Regex.Replace(str, "日", "");            Console.WriteLine(str);            //解法二            string str1 = "2013年9月9日";            //正则表达式中,凡是组里面的数组,都可以用"$组号"进行引用            str1 = Regex.Replace(str1,@"(\d+)年(\d+)月(\d+)日","$1-$2-$3");            Console.WriteLine(str1);            //“$组号”引用匹配组的再举例            string str2=Regex.Replace("123",@"\d","$0$0");            Console.WriteLine(str2);            Console.ReadKey();
  • 匹配替换案例:

1.“压缩”文件(简单压缩)

//要缩文件,将js文本中的空格及注释都去掉。            string txt = System.IO.File.ReadAllText(@"E:\上课\第12天\课堂代码\正则表达式的替换\bin\Debug\jkuery_20131031.js");            txt = Regex.Replace(txt, @"//.+", "");            txt = Regex.Replace(txt,@"\s+","");            System.IO.File.WriteAllText(@"E:\上课\第12天\课堂代码\正则表达式的替换\bin\Debug\结果.js",txt);            //我们还可以分析词法,将所有变量名都替换掉

 2.将网址文本改为链接网址

       string text = System.IO.File.ReadAllText("网址大全.txt", Encoding.Default);            string regex1 = @".+";            text = Regex.Replace(text, regex1, "$0");//直接加链接            System.IO.File.WriteAllText(@"E:\上课\第12天\课堂代码\课堂练习\bin\Debug\结果.txt1", text);            string regex = @"(https://)?(.+)";            text=Regex.Replace(text,regex,"$2");//让所有链接前都有一个http://            System.IO.File.WriteAllText(@"E:\上课\第12天\课堂代码\课堂练习\bin\Debug\结果.txt", text);

 3.给文件名加后一个缀

      Console.WriteLine("请输入一个文件名");            string str = Console.ReadLine();            str=Regex.Replace(str,@"(.+)\.(.+)","$1_mim.$2");            Console.WriteLine(str);            Console.ReadKey();

 

 

转载于:https://www.cnblogs.com/tobecabbage/p/3537523.html

你可能感兴趣的文章
eclipse启动无响应,停留在Loading workbench状态
查看>>
How exactly does Google AdWords work?
查看>>
多线程系列(4)使用多线程的安全问题
查看>>
C# 你可能没这样用过(逗逼方式) return
查看>>
387. First Unique Character in a String
查看>>
JSP、Servlet乱码终极解决方案
查看>>
旅途上看的电影和观后感
查看>>
qt实现类似QQ伸缩窗口--鼠标事件应用
查看>>
Ztree异步树加载
查看>>
复杂问题的简单抽象:魔兽世界中的兔子们
查看>>
UVA 10529-Dumb Bones(概率dp)
查看>>
关于IE和火狐,谷歌,Safari对Html标签Object和Embed的支持问题
查看>>
MyEclipse DB Browser使用图文全攻略
查看>>
poj3320 Jessica's Reading Problem(尺取思路+STL)
查看>>
A - Vasya and Socks
查看>>
项目管理、设计开发、代码管理、bug管理工具介绍
查看>>
分布式计算开源框架Hadoop介绍
查看>>
安卓平台接口剖析
查看>>
linux文件编码查看与修改
查看>>
[Java] 系统环境变量配置
查看>>